package com.zofer.study.stream;

import com.zofer.study.stream.entity.Dish;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 对象列表
 */
public class StreamTest02 {

    static List<Dish> menu = Arrays.asList(
            new Dish("pork", false, 800, Dish.Type.MEAT),
            new Dish("beef", false, 700, Dish.Type.MEAT),
            new Dish("chicken", false, 400, Dish.Type.MEAT),
            new Dish("french fries", true, 530, Dish.Type.OTHER),
            new Dish("rice", true, 350, Dish.Type.OTHER),
            new Dish("season fruit", true, 120, Dish.Type.OTHER),
            new Dish("pizza", true, 550, Dish.Type.OTHER),
            new Dish("salmon", false, 300, Dish.Type.FISH),
            new Dish("salmon", false, 450, Dish.Type.FISH) );

    public static void main(String[] args) {
        test1();
//        test2();
        test3();
        test4();
        test5();
        test6();
        test7();
    }

    /**
     * filter > sorted
     */
    public static void test1(){
        List<Integer> list = menu.stream()
                .filter(dish -> dish.getCalories() > 300)
                .sorted(Comparator.comparing(Dish::getCalories).reversed())
                .map(Dish::getCalories)
                .limit(3)
                .collect(Collectors.toList());

        System.out.println(list);
    }


    /**
     * list to map
     */
    public static void test2(){
        //list to map
        Map<String,Integer> map1 = menu.stream().collect(Collectors.toMap(Dish::getName,Dish::getCalories));
        System.out.println(map1);

        Map<String,Dish> map2 = menu.stream().collect(Collectors.toMap(Dish::getName,dish -> dish));
        System.out.println(map2);

        // key重复报错
        Map<String,Dish> map3 = menu.stream().collect(Collectors.toMap(Dish::getName, Function.identity(),(dish1,dish2) -> dish2));
        System.out.println(map3);

    }


    /**
     * list 使用自定义方法
     */
    public static void test3(){
        List<Dish> list = menu.stream().filter(x -> editName(x)).collect(Collectors.toList());
        System.out.println(list);
    }


    public static boolean editName(Dish dish){
        if (dish.getCalories() > 300){
            return true;
        }
        return false;
    }

    public enum CaloricLevel { DIET, NORMAL, FAT }

    /**
     * list groupby map
     */
    public static void test4(){
        Map<String,List<Dish>> map = menu.stream().collect(Collectors.groupingBy(Dish::getName));
        System.out.println("========");

        Map<CaloricLevel, List<Dish>> dishesByCaloricLevel =
                menu.stream()
                        .collect(Collectors.groupingBy(dish -> {
                                    if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                                    else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                                    else return CaloricLevel.FAT;
                                }));

        // 自定义方法进行分组
        Map<CaloricLevel, List<Dish>> dishesByCaloricLevel2 =
                menu.stream()
                        .collect(Collectors.groupingBy(dish -> groupingBy4(dish)));

        // 获取每组的数量
        Map<Dish.Type, Long> typesCount = menu.stream().collect(
                Collectors.groupingBy(Dish::getType, Collectors.counting()));

        // 获取每组最大值的对象Map
        Map<Dish.Type, Optional<Dish>> mostCaloricByType =
                menu.stream()
                        .collect(Collectors.groupingBy(Dish::getType,
                                Collectors.maxBy(Comparator.comparingInt(Dish::getCalories))));

        // 二级分组
        Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel =
                menu.stream().collect(
                        Collectors.groupingBy(Dish::getType,
                                Collectors.groupingBy(dish -> {
                                    if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                                    else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                                    else return CaloricLevel.FAT;
                                } )
                        )
                );

        System.out.println("=========2====");
    }


    /**
     *
     */
    public static CaloricLevel groupingBy4(Dish dish){
        if (dish.getCalories() <= 400) return CaloricLevel.DIET;
        else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
        else return CaloricLevel.FAT;
    }


    /**
     * match
     */
    public static void test5(){
        boolean ismatch1 = menu.stream().map(Dish::getName).noneMatch(x -> x.equals("pork"));
        System.out.println(ismatch1);
    }


    /**
     * find
     */
    public static void test6(){
        Optional<Dish> str  = menu.stream().filter(s -> s.getName().equals("pork")).findAny();
        System.out.println(str.get());

        boolean isPresent  = menu.stream().filter(s -> s.getName().equals("pork")).findAny().isPresent();
        System.out.println(isPresent);
    }


    /**
     * reduce
     */
    public static void test7(){
        int sum = menu.stream().map(Dish::getCalories).reduce(0,(a,b) -> a+b);
        System.out.println(sum);

        Optional<Integer> op = menu.stream().map(Dish::getCalories).reduce((a,b) -> a+b);
        System.out.println(op.get());

        int max = menu.stream().map(Dish::getCalories).reduce(0,Integer::max);
        System.out.println(max);
    }

}
